@heyramzi/ui 2.11.1 → 2.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/helpers.js +38 -38
- package/dist/agents/page-state.js +49 -50
- package/dist/agents/vendor/color.js +146 -127
- package/dist/agents/vendor/draw.js +617 -508
- package/dist/agents/vendor/engine.js +698 -599
- package/dist/agents/vendor/mesh.js +653 -683
- package/dist/agents/vendor/plastic.js +3913 -3112
- package/dist/agents/vendor/presets.js +163 -164
- package/dist/agents/vendor/shapes.js +21 -20
- package/dist/agents/vendor/ticker.js +41 -42
- package/dist/agents/vendor/types.js +1 -0
- package/dist/agents/vendor/wear.js +1421 -1448
- package/dist/ai/confirmation/confirmation-context.svelte.js +6 -6
- package/dist/ai/confirmation/index.js +3 -1
- package/dist/ai/index.js +33 -0
- package/dist/ai/prompt-input/index.js +3 -1
- package/dist/ai/reasoning/index.js +3 -1
- package/dist/ai/reasoning/reasoning-context.svelte.js +6 -6
- package/dist/ai/suggestion/index.js +3 -1
- package/dist/ai/typing-dots/index.js +3 -1
- package/dist/animations/text-swap.js +24 -24
- package/dist/brand/index.js +54 -48
- package/dist/canvas/card/resize.js +5 -3
- package/dist/canvas/edges/edge-path.js +255 -242
- package/dist/canvas/editor/context-menu.js +39 -36
- package/dist/canvas/editor/dispatch.svelte.js +154 -151
- package/dist/canvas/editor/editor-context.js +7 -2
- package/dist/canvas/editor/editor-mode.js +1 -0
- package/dist/canvas/editor/frame.js +73 -76
- package/dist/canvas/editor/hand-context.js +5 -2
- package/dist/canvas/editor/history-core.js +163 -191
- package/dist/canvas/editor/keymap.js +95 -169
- package/dist/canvas/editor/layout-actions.js +143 -144
- package/dist/canvas/editor/lock.js +52 -51
- package/dist/canvas/editor/rebase.js +217 -240
- package/dist/canvas/editor/style.js +132 -137
- package/dist/canvas/editor/text-field-context.js +7 -2
- package/dist/canvas/editor/z-order.js +65 -70
- package/dist/canvas/headless/alignment.js +22 -16
- package/dist/canvas/headless/break-apart-find.js +286 -279
- package/dist/canvas/headless/break-apart-pieces.js +62 -58
- package/dist/canvas/headless/break-apart-plan.js +299 -325
- package/dist/canvas/headless/break-apart-style.js +75 -70
- package/dist/canvas/headless/break-apart.js +188 -181
- package/dist/canvas/headless/canvas-cleanup.js +78 -58
- package/dist/canvas/headless/edge-anchors.js +115 -116
- package/dist/canvas/headless/edge-memo.js +24 -22
- package/dist/canvas/headless/edge-serialization.js +17 -27
- package/dist/canvas/headless/figure-geometry.js +232 -264
- package/dist/canvas/headless/fit-viewport.js +84 -67
- package/dist/canvas/headless/grid.js +88 -86
- package/dist/canvas/headless/icon-node.js +44 -36
- package/dist/canvas/headless/index.js +1 -0
- package/dist/canvas/headless/linkify.js +17 -19
- package/dist/canvas/headless/pen-marks.js +101 -95
- package/dist/canvas/headless/sketch.js +231 -209
- package/dist/canvas/headless/snap-guides.js +99 -83
- package/dist/canvas/headless/svg-figure.js +133 -117
- package/dist/canvas/headless/table-layout.js +146 -107
- package/dist/canvas/index.js +2 -0
- package/dist/canvas/lod/lod-mode.svelte.js +20 -18
- package/dist/canvas/lod/render-all.svelte.js +36 -39
- package/dist/canvas/ops/arrange.js +78 -71
- package/dist/canvas/ops/ops.js +260 -255
- package/dist/canvas/pen/colors.js +37 -35
- package/dist/canvas/pen/eraser.js +28 -27
- package/dist/canvas/pen/geometry.js +120 -130
- package/dist/canvas/pen/index.js +1 -0
- package/dist/canvas/pen/ops.js +11 -11
- package/dist/canvas/pen/pen-session.js +150 -159
- package/dist/canvas/pen/plugin.js +107 -104
- package/dist/canvas/pen/shapes.js +73 -68
- package/dist/canvas/pen/stroke-path.js +32 -30
- package/dist/canvas/pen/types.js +21 -21
- package/dist/canvas/pen/ui.js +10 -8
- package/dist/canvas/plugin.js +46 -46
- package/dist/canvas/screen/glyphs.js +12 -11
- package/dist/canvas/screen/labels.js +22 -22
- package/dist/canvas/screen/parts.js +98 -111
- package/dist/canvas/screen/plugin.js +47 -56
- package/dist/canvas/screen/types.js +30 -35
- package/dist/canvas/screen/ui.js +7 -7
- package/dist/canvas/test-utils.js +14 -14
- package/dist/canvas/types.js +1 -0
- package/dist/canvas/ui/forward-wheel.js +24 -25
- package/dist/canvas/ui/icons.js +64 -131
- package/dist/canvas/ui/place-panel.js +58 -49
- package/dist/canvas/ui/shortcut-tip.js +14 -12
- package/dist/canvas/ui/tools.js +300 -385
- package/dist/charts/dashboard/chart.js +4 -0
- package/dist/charts/dashboard/data-table.js +11 -0
- package/dist/charts/dashboard/windows.js +8 -3
- package/dist/charts/edge-fade.js +10 -5
- package/dist/charts/hover-band.js +16 -11
- package/dist/charts/index.js +0 -1
- package/dist/charts/motion.js +11 -7
- package/dist/charts/primitives/chart-utils.js +12 -12
- package/dist/components/copy/clipboard.js +32 -32
- package/dist/components/copy/copied.svelte.js +31 -23
- package/dist/components/data-table/data-table.js +39 -39
- package/dist/components/docs/index.js +4 -0
- package/dist/components/docs/scroll-spy.svelte.js +73 -68
- package/dist/components/list-page/filter-section.js +4 -1
- package/dist/components/list-page/index.js +2 -0
- package/dist/components/list-page/list-table.js +7 -2
- package/dist/components/list-page/queue-rail.js +14 -0
- package/dist/components/list-page/section-host.js +4 -2
- package/dist/components/list-page/step.js +4 -3
- package/dist/components/list-page/types.js +1 -0
- package/dist/components/picker/trigger.js +48 -30
- package/dist/components/picker/types.js +1 -0
- package/dist/components/segmented/collapse.js +38 -27
- package/dist/components/segmented/index.js +8 -0
- package/dist/components/segmented/segmented.js +67 -42
- package/dist/components/star-rating-input/index.js +3 -1
- package/dist/components/table-view/types.js +1 -0
- package/dist/components/tags-input/tags.js +81 -69
- package/dist/components/theme/index.js +4 -0
- package/dist/components/toolbar/index.js +4 -0
- package/dist/components/toolbar/toolbar-trigger.js +14 -1
- package/dist/editor/anchors.js +17 -13
- package/dist/editor/block-id.js +52 -51
- package/dist/editor/block-ops.js +108 -80
- package/dist/editor/doc-blocks.js +155 -166
- package/dist/editor/extensions.js +139 -180
- package/dist/editor/index.js +4 -0
- package/dist/editor/markdown-test-helpers.js +4 -2
- package/dist/editor/markdown.js +420 -408
- package/dist/editor/serializer.js +204 -200
- package/dist/editor/slash-items.js +89 -101
- package/dist/editor/youtube-url.js +25 -20
- package/dist/effects/animated-beam/path-calculator.svelte.js +43 -38
- package/dist/effects/animated-beam/types.js +1 -0
- package/dist/effects/border-beam/css.js +92 -78
- package/dist/effects/border-beam/presets.js +1705 -1720
- package/dist/effects/border-beam/register-properties.js +43 -33
- package/dist/effects/border-beam/types.js +1 -0
- package/dist/effects/image-comparison/compare.js +3 -2
- package/dist/effects/image-reveal/types.js +1 -0
- package/dist/effects/magnetic/magnetic.js +58 -52
- package/dist/effects/reveal/observe.js +50 -40
- package/dist/effects/reveal/types.js +1 -0
- package/dist/effects/shader-gradient/color.js +36 -29
- package/dist/effects/shader-gradient/renderer.js +384 -295
- package/dist/effects/shader-gradient/shaders.js +31 -0
- package/dist/effects/shader-gradient/types.js +1 -0
- package/dist/icons/apple-symbol-exports.js +99 -124
- package/dist/icons/sf-symbols.js +357 -461
- package/dist/icons/trades.js +43 -28
- package/dist/inbox/index.js +1 -0
- package/dist/inbox/logic.js +126 -122
- package/dist/inbox/types.js +43 -43
- package/dist/lib/arrive.js +19 -12
- package/dist/lib/icon-types.js +1 -0
- package/dist/lib/initials.js +16 -10
- package/dist/lib/layout.js +5 -0
- package/dist/lib/panel.js +13 -0
- package/dist/lib/result.js +22 -22
- package/dist/lib/sliding-pill.js +59 -44
- package/dist/lib/theme-transition.js +43 -43
- package/dist/lib/tone.js +31 -24
- package/dist/lib/utils.js +3 -1
- package/dist/onboarding/define-tours.js +24 -23
- package/dist/onboarding/onboarding.svelte.js +16 -12
- package/dist/onboarding/pick.js +10 -6
- package/dist/onboarding/stores.js +40 -41
- package/dist/onboarding/wait.js +24 -23
- package/dist/panel/side-panel-types.js +1 -0
- package/dist/record/demo-data.js +459 -486
- package/dist/record/fields.js +129 -131
- package/dist/record/format.js +70 -82
- package/dist/record/gutter.js +1 -0
- package/dist/record/kinds.js +95 -105
- package/dist/record/logic.js +238 -219
- package/dist/record/types.js +49 -48
- package/dist/shadcn/accordion/index.js +3 -1
- package/dist/shadcn/alert/index.js +3 -1
- package/dist/shadcn/alert-dialog/index.js +3 -1
- package/dist/shadcn/attachment/index.js +3 -1
- package/dist/shadcn/avatar/index.js +3 -1
- package/dist/shadcn/breadcrumb/index.js +3 -1
- package/dist/shadcn/bubble/index.js +3 -1
- package/dist/shadcn/button/index.js +3 -1
- package/dist/shadcn/calendar/index.js +3 -1
- package/dist/shadcn/card/index.js +3 -1
- package/dist/shadcn/checkbox/index.js +3 -1
- package/dist/shadcn/code-block/index.js +3 -1
- package/dist/shadcn/collapsible/index.js +3 -1
- package/dist/shadcn/command/index.js +4 -1
- package/dist/shadcn/context-menu/index.js +3 -1
- package/dist/shadcn/dialog/index.js +3 -1
- package/dist/shadcn/dropdown-menu/menu-item.js +40 -20
- package/dist/shadcn/empty/index.js +3 -1
- package/dist/shadcn/field/index.js +3 -1
- package/dist/shadcn/hooks/highlighter.js +77 -75
- package/dist/shadcn/hooks/is-mobile.svelte.js +3 -3
- package/dist/shadcn/hooks/use-highlighted-code.svelte.js +62 -62
- package/dist/shadcn/input/index.js +3 -1
- package/dist/shadcn/kbd/index.js +3 -1
- package/dist/shadcn/label/index.js +3 -1
- package/dist/shadcn/marker/index.js +3 -1
- package/dist/shadcn/message/index.js +3 -1
- package/dist/shadcn/message-scroller/index.js +3 -1
- package/dist/shadcn/popover/index.js +3 -1
- package/dist/shadcn/progress/index.js +3 -1
- package/dist/shadcn/progress/tone.js +8 -7
- package/dist/shadcn/radio-group/index.js +3 -1
- package/dist/shadcn/scroll-area/index.js +3 -1
- package/dist/shadcn/select/index.js +3 -1
- package/dist/shadcn/separator/index.js +3 -1
- package/dist/shadcn/sheet/index.js +3 -1
- package/dist/shadcn/sidebar/context.svelte.js +42 -28
- package/dist/shadcn/sidebar/index.js +3 -1
- package/dist/shadcn/skeleton/index.js +3 -1
- package/dist/shadcn/slider/index.js +3 -1
- package/dist/shadcn/switch/index.js +3 -1
- package/dist/shadcn/table/index.js +3 -1
- package/dist/shadcn/tabs/index.js +3 -1
- package/dist/shadcn/textarea/index.js +3 -1
- package/dist/shadcn/toggle/index.js +3 -1
- package/dist/shadcn/toggle-group/index.js +3 -1
- package/dist/shadcn/tooltip/context.js +7 -2
- package/dist/shadcn/tooltip/index.js +3 -1
- package/dist/shadcn/trace/index.js +3 -1
- package/dist/slides/bridges.js +65 -59
- package/dist/slides/deck-controller.svelte.js +210 -207
- package/dist/slides/export/capture.js +66 -71
- package/dist/slides/export/ffmpeg.js +76 -72
- package/dist/slides/export/index.js +3 -0
- package/dist/slides/export/launch.js +9 -6
- package/dist/slides/export/pdf.js +60 -54
- package/dist/slides/export/types.js +1 -0
- package/dist/slides/labels.js +24 -24
- package/dist/slides/layout.js +39 -41
- package/dist/slides/model.js +9 -7
- package/dist/slides/navigation.js +78 -73
- package/dist/slides/types.js +2 -2
- package/dist/status/define-statuses.js +18 -14
- package/dist/status/status-types.js +1 -0
- package/dist/test-setup.js +24 -20
- package/dist/thread/logic.js +73 -77
- package/dist/thread/types.js +21 -21
- package/dist/work/board-order.js +94 -90
- package/dist/work/dates.js +16 -9
- package/dist/work/detail/detail-types.js +18 -18
- package/dist/work/docs/edited.js +32 -29
- package/dist/work/docs/index.js +4 -0
- package/dist/work/docs/labels.js +34 -34
- package/dist/work/docs/menu.js +113 -106
- package/dist/work/docs/outline.js +39 -29
- package/dist/work/gantt/logic.js +211 -235
- package/dist/work/inbox/inbox-logic.js +71 -75
- package/dist/work/inbox/inbox-statuses.js +75 -72
- package/dist/work/inbox/inbox-types.js +1 -0
- package/dist/work/kanban-drag.js +27 -22
- package/dist/work/kanban-types.js +1 -0
- package/dist/work/presets/sales.js +36 -32
- package/dist/work/reorder.js +9 -8
- package/dist/work/task-types.js +1 -0
- package/dist/work/time/duration.js +51 -46
- package/dist/work/time/time-types.js +23 -23
- package/dist/work/use-kanban-dnd.svelte.js +126 -125
- package/package.json +3 -1
- package/src/components/list-page/master-detail.svelte +3 -1
- package/src/components/list-page/rail-row.svelte +4 -4
- package/src/editor/markdown.ts +30 -35
package/dist/agents/helpers.js
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
+
/* Pure helpers for the avatar: numbers, theme, lights, idle scheduling. */
|
|
1
2
|
import { DARK_INK, LIGHT_INK, luminance } from "./vendor/color.js";
|
|
2
3
|
import { stockLights } from "./vendor/plastic.js";
|
|
3
|
-
const contrast = (a, b)=>(Math.max(a, b) +
|
|
4
|
+
const contrast = (a, b) => (Math.max(a, b) + .05) / (Math.min(a, b) + .05);
|
|
5
|
+
/** Off-black or off-white eyes, whichever reads stronger on the body: the vendor's fixed cutoff left 2:1 eyes on mid blues. */
|
|
4
6
|
export function inkFor(body) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
const l = luminance(body);
|
|
8
|
+
return contrast(l, luminance(DARK_INK)) >= contrast(l, luminance(LIGHT_INK)) ? DARK_INK : LIGHT_INK;
|
|
7
9
|
}
|
|
8
|
-
export const clamp = (v, lo, hi)=>Math.min(hi, Math.max(lo, Number.isFinite(v) ? v : 1));
|
|
9
|
-
export const q = (v, lo, hi)=>Math.round(clamp(v, lo, hi) * 20) / 20;
|
|
10
|
-
export const clampOpt = (v, d, lo, hi)=>clamp(v ?? d, lo, hi);
|
|
11
|
-
export const deviceDpr = ()=>Math.min(2, typeof devicePixelRatio === "number" && devicePixelRatio || 1);
|
|
10
|
+
export const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, Number.isFinite(v) ? v : 1));
|
|
11
|
+
export const q = (v, lo, hi) => Math.round(clamp(v, lo, hi) * 20) / 20;
|
|
12
|
+
export const clampOpt = (v, d, lo, hi) => clamp(v ?? d, lo, hi);
|
|
13
|
+
export const deviceDpr = () => Math.min(2, typeof devicePixelRatio === "number" && devicePixelRatio || 1);
|
|
12
14
|
export function hashSeed(id) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
let h = 2166136261;
|
|
16
|
+
for (let i = 0; i < id.length; i++) h = Math.imul(h ^ id.charCodeAt(i), 16777619);
|
|
17
|
+
return (h >>> 0) % 1e3 / 1e3;
|
|
16
18
|
}
|
|
17
|
-
export const reducedMotion = ()=>typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
19
|
+
export const reducedMotion = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
18
20
|
export function resolveTheme(theme, el) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
if (theme !== "auto") return theme;
|
|
22
|
+
const host = el?.closest("[data-theme], .dark, .light");
|
|
23
|
+
if (host) {
|
|
24
|
+
const v = host.getAttribute("data-theme");
|
|
25
|
+
if (v === "dark" || v === "light") return v;
|
|
26
|
+
if (host.classList.contains("dark")) return "dark";
|
|
27
|
+
if (host.classList.contains("light")) return "light";
|
|
28
|
+
}
|
|
29
|
+
return typeof matchMedia === "function" && matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark";
|
|
28
30
|
}
|
|
29
31
|
export function lightsFor(lightAt, backLight, lightFront) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
];
|
|
37
|
-
if (lightFront !== undefined) lights.front = Math.min(85, Math.max(0, lightFront)) * Math.PI / 180;
|
|
38
|
-
return lights;
|
|
32
|
+
const a = lightAt * Math.PI / 180;
|
|
33
|
+
const b = (backLight ?? 0) * Math.PI / 180;
|
|
34
|
+
const lights = stockLights(Math.sin(a), -Math.cos(a));
|
|
35
|
+
if (backLight !== undefined) [lights.bx, lights.by] = [Math.sin(b), -Math.cos(b)];
|
|
36
|
+
if (lightFront !== undefined) lights.front = Math.min(85, Math.max(0, lightFront)) * Math.PI / 180;
|
|
37
|
+
return lights;
|
|
39
38
|
}
|
|
40
39
|
export function warmIdle(fn) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
if (typeof requestIdleCallback === "function") {
|
|
41
|
+
const id = requestIdleCallback(fn);
|
|
42
|
+
return () => cancelIdleCallback(id);
|
|
43
|
+
}
|
|
44
|
+
const id = setTimeout(fn, 1);
|
|
45
|
+
return () => clearTimeout(id);
|
|
47
46
|
}
|
|
47
|
+
/* Full pull up close, fading to nothing by 3 head widths. */
|
|
48
48
|
export function pointerStrength(d) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
if (d < 1) return 1;
|
|
50
|
+
if (d > 3) return 0;
|
|
51
|
+
return 1 - (d - 1) / 2;
|
|
52
52
|
}
|
|
@@ -1,65 +1,64 @@
|
|
|
1
|
+
/* What every avatar on the page shares: the batching shown-gate, so a row of
|
|
2
|
+
them comes in together, the path caches, and one theme watcher. */
|
|
1
3
|
import { bakesPending } from "./vendor/plastic.js";
|
|
2
|
-
export const SHOW_WITHIN =
|
|
4
|
+
export const SHOW_WITHIN = 4e3;
|
|
3
5
|
export const waiters = new Map();
|
|
4
6
|
export function showReady() {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
waiters.clear();
|
|
11
|
-
for (const w of all)w.show();
|
|
7
|
+
if (bakesPending()) return;
|
|
8
|
+
for (const w of waiters.values()) if (!w.ready()) return;
|
|
9
|
+
const all = [...waiters.values()];
|
|
10
|
+
waiters.clear();
|
|
11
|
+
for (const w of all) w.show();
|
|
12
12
|
}
|
|
13
13
|
const pathCache = new Map();
|
|
14
14
|
export function bodyPath(d) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
let p = pathCache.get(d);
|
|
16
|
+
if (!p) {
|
|
17
|
+
p = new Path2D(d);
|
|
18
|
+
pathCache.set(d, p);
|
|
19
|
+
}
|
|
20
|
+
return p;
|
|
21
21
|
}
|
|
22
22
|
const partsCache = new Map();
|
|
23
23
|
export function partPaths(d) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
let p = partsCache.get(d);
|
|
25
|
+
if (!p) {
|
|
26
|
+
p = d.split(/(?=M)/).filter((s) => s.trim()).map((s) => new Path2D(s));
|
|
27
|
+
partsCache.set(d, p);
|
|
28
|
+
}
|
|
29
|
+
return p;
|
|
30
30
|
}
|
|
31
31
|
let uidSeq = 0;
|
|
32
|
-
export const nextUid = ()
|
|
32
|
+
export const nextUid = () => `ba-${++uidSeq}`;
|
|
33
|
+
/* One observer for the whole page: a `.dark` or `data-theme` flip on
|
|
34
|
+
<html> or <body>, or the OS scheme changing, repaints every auto avatar. */
|
|
33
35
|
const themeListeners = new Set();
|
|
34
36
|
let themeWatch = null;
|
|
35
37
|
export function onThemeChange(fn) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
themeWatch = null;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
38
|
+
themeListeners.add(fn);
|
|
39
|
+
if (!themeWatch && typeof MutationObserver === "function" && typeof document !== "undefined") {
|
|
40
|
+
const fire = () => {
|
|
41
|
+
for (const l of themeListeners) l();
|
|
42
|
+
};
|
|
43
|
+
const mo = new MutationObserver(fire);
|
|
44
|
+
const opts = {
|
|
45
|
+
attributes: true,
|
|
46
|
+
attributeFilter: ["class", "data-theme"]
|
|
47
|
+
};
|
|
48
|
+
mo.observe(document.documentElement, opts);
|
|
49
|
+
if (document.body) mo.observe(document.body, opts);
|
|
50
|
+
const mq = typeof matchMedia === "function" ? matchMedia("(prefers-color-scheme: dark)") : null;
|
|
51
|
+
mq?.addEventListener("change", fire);
|
|
52
|
+
themeWatch = () => {
|
|
53
|
+
mo.disconnect();
|
|
54
|
+
mq?.removeEventListener("change", fire);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return () => {
|
|
58
|
+
themeListeners.delete(fn);
|
|
59
|
+
if (themeListeners.size === 0 && themeWatch) {
|
|
60
|
+
themeWatch();
|
|
61
|
+
themeWatch = null;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
65
64
|
}
|
|
@@ -1,149 +1,168 @@
|
|
|
1
|
+
// @ts-nocheck WHY: vendored engine, kept as upstream wrote it so a re-sync stays a clean diff. Strict flags in consumers (review) would flag ~870 spots.
|
|
2
|
+
/** Parse #rgb / #rrggbb / rgb() / hsl() into 0–255 channels; null for anything else. */
|
|
1
3
|
export function parseColor(input) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
4
|
+
const s = input.trim();
|
|
5
|
+
const hsl = s.match(/^hsla?\(\s*([\d.]+)(?:deg)?[,\s]+([\d.]+)%[,\s]+([\d.]+)%/i);
|
|
6
|
+
if (hsl) return hslToRgb([
|
|
7
|
+
Number(hsl[1]) / 360,
|
|
8
|
+
Number(hsl[2]) / 100,
|
|
9
|
+
Number(hsl[3]) / 100
|
|
10
|
+
]);
|
|
11
|
+
const hex = s.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
|
|
12
|
+
if (hex) {
|
|
13
|
+
let h = hex[1];
|
|
14
|
+
if (h.length === 3) h = h.split("").map((c) => c + c).join("");
|
|
15
|
+
const n = parseInt(h, 16);
|
|
16
|
+
return [
|
|
17
|
+
n >> 16 & 255,
|
|
18
|
+
n >> 8 & 255,
|
|
19
|
+
n & 255
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
const rgb = s.match(/^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)/i);
|
|
23
|
+
if (rgb) return [
|
|
24
|
+
Number(rgb[1]),
|
|
25
|
+
Number(rgb[2]),
|
|
26
|
+
Number(rgb[3])
|
|
27
|
+
];
|
|
28
|
+
return null;
|
|
27
29
|
}
|
|
30
|
+
/** Relative luminance (WCAG), 0–1. Unparseable colours count as mid-grey. */
|
|
28
31
|
export function luminance(color) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const c = parseColor(color);
|
|
33
|
+
if (!c) return .5;
|
|
34
|
+
const lin = (v) => {
|
|
35
|
+
const x = v / 255;
|
|
36
|
+
return x <= .03928 ? x / 12.92 : ((x + .055) / 1.055) ** 2.4;
|
|
37
|
+
};
|
|
38
|
+
return .2126 * lin(c[0]) + .7152 * lin(c[1]) + .0722 * lin(c[2]);
|
|
36
39
|
}
|
|
37
40
|
export const DARK_INK = "#1E1A33";
|
|
38
41
|
export const LIGHT_INK = "#F7F5F2";
|
|
42
|
+
/** Face ink for a body colour: dark ink, or light ink on a dark body. */
|
|
39
43
|
export function autoInk(color) {
|
|
40
|
-
|
|
44
|
+
return luminance(color) < .13 ? LIGHT_INK : DARK_INK;
|
|
41
45
|
}
|
|
46
|
+
/* ── HSL, for the body's shades ─────────────────────────────────────── */
|
|
42
47
|
function rgbToHsl([r, g, b]) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
48
|
+
r /= 255;
|
|
49
|
+
g /= 255;
|
|
50
|
+
b /= 255;
|
|
51
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
|
52
|
+
const l = (max + min) / 2;
|
|
53
|
+
if (max === min) return [
|
|
54
|
+
0,
|
|
55
|
+
0,
|
|
56
|
+
l
|
|
57
|
+
];
|
|
58
|
+
const d = max - min;
|
|
59
|
+
const s = l > .5 ? d / (2 - max - min) : d / (max + min);
|
|
60
|
+
let h = 0;
|
|
61
|
+
if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
|
|
62
|
+
else if (max === g) h = (b - r) / d + 2;
|
|
63
|
+
else h = (r - g) / d + 4;
|
|
64
|
+
return [
|
|
65
|
+
h / 6,
|
|
66
|
+
s,
|
|
67
|
+
l
|
|
68
|
+
];
|
|
64
69
|
}
|
|
65
70
|
function hslToRgb([h, s, l]) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
71
|
+
if (s === 0) return [
|
|
72
|
+
l * 255,
|
|
73
|
+
l * 255,
|
|
74
|
+
l * 255
|
|
75
|
+
];
|
|
76
|
+
const q = l < .5 ? l * (1 + s) : l + s - l * s;
|
|
77
|
+
const p = 2 * l - q;
|
|
78
|
+
const f = (t) => {
|
|
79
|
+
t = (t % 1 + 1) % 1;
|
|
80
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
81
|
+
if (t < 1 / 2) return q;
|
|
82
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
83
|
+
return p;
|
|
84
|
+
};
|
|
85
|
+
return [
|
|
86
|
+
f(h + 1 / 3) * 255,
|
|
87
|
+
f(h) * 255,
|
|
88
|
+
f(h - 1 / 3) * 255
|
|
89
|
+
];
|
|
85
90
|
}
|
|
86
91
|
function hslToCss([h, s, l]) {
|
|
87
|
-
|
|
92
|
+
return `hsl(${(h * 360).toFixed(1)} ${(s * 100).toFixed(1)}% ${(l * 100).toFixed(1)}%)`;
|
|
88
93
|
}
|
|
89
|
-
const clamp01 = (v)=>Math.min(1, Math.max(0, v));
|
|
94
|
+
const clamp01 = (v) => Math.min(1, Math.max(0, v));
|
|
95
|
+
/**
|
|
96
|
+
* A shade of a colour: `dl` moves the lightness (−1..1), `ds` the
|
|
97
|
+
* saturation. Darker shades get a touch more saturation so they stay
|
|
98
|
+
* rich instead of going grey, the way a painted surface falls into shadow.
|
|
99
|
+
*/
|
|
90
100
|
export function shade(color, dl, ds = 0) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
const c = parseColor(color);
|
|
102
|
+
if (!c) return color;
|
|
103
|
+
const [h, s, l] = rgbToHsl(c);
|
|
104
|
+
return hslToCss([
|
|
105
|
+
h,
|
|
106
|
+
clamp01(s + ds + (dl < 0 ? -dl * .25 : 0)),
|
|
107
|
+
clamp01(l + dl)
|
|
108
|
+
]);
|
|
99
109
|
}
|
|
100
|
-
|
|
101
|
-
const
|
|
110
|
+
/* OKLab, for moving a colour along its own hue (Björn Ottosson's) */
|
|
111
|
+
const toLinear = (u) => u <= .04045 ? u / 12.92 : Math.pow((u + .055) / 1.055, 2.4);
|
|
112
|
+
const toSrgb = (u) => u <= .0031308 ? 12.92 * u : 1.055 * Math.pow(u, 1 / 2.4) - .055;
|
|
102
113
|
function oklab(r, g, b) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
const l = Math.cbrt(.4122214708 * r + .5363325363 * g + .0514459929 * b);
|
|
115
|
+
const m = Math.cbrt(.2119034982 * r + .6806995451 * g + .1073969566 * b);
|
|
116
|
+
const s = Math.cbrt(.0883024619 * r + .2817188376 * g + .6299787005 * b);
|
|
117
|
+
return [
|
|
118
|
+
.2104542553 * l + .793617785 * m - .0040720468 * s,
|
|
119
|
+
1.9779984951 * l - 2.428592205 * m + .4505937099 * s,
|
|
120
|
+
.0259040371 * l + .7827717662 * m - .808675766 * s
|
|
121
|
+
];
|
|
111
122
|
}
|
|
112
123
|
function fromOklab(L, a, b) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
const l = Math.pow(L + .3963377774 * a + .2158037573 * b, 3);
|
|
125
|
+
const m = Math.pow(L - .1055613458 * a - .0638541728 * b, 3);
|
|
126
|
+
const s = Math.pow(L - .0894841775 * a - 1.291485548 * b, 3);
|
|
127
|
+
return [
|
|
128
|
+
4.0767416621 * l - 3.3077115913 * m + .2309699292 * s,
|
|
129
|
+
-1.2684380046 * l + 2.6097574011 * m - .3413193965 * s,
|
|
130
|
+
-.0041960863 * l - .7034186147 * m + 1.707614701 * s
|
|
131
|
+
];
|
|
121
132
|
}
|
|
122
|
-
const inGamut = (c)=>c.every((v)=>v >= -1e-4 && v <= 1 + 1e-4);
|
|
133
|
+
const inGamut = (c) => c.every((v) => v >= -1e-4 && v <= 1 + 1e-4);
|
|
134
|
+
/** A more vivid version of a colour, `t` 0–1: its chroma raised along its
|
|
135
|
+
own hue (in OKLab) by up to half again. Where the screen cannot show that
|
|
136
|
+
at the same lightness, the colour deepens a little — by at most 15% of
|
|
137
|
+
its lightness — toward the hue's most vivid shade (a sky blue toward a
|
|
138
|
+
royal one), and the chroma stops at whatever the screen can show. */
|
|
123
139
|
export function richer(color, t) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
140
|
+
const c = parseColor(color);
|
|
141
|
+
if (!c || !(t > 0)) return color;
|
|
142
|
+
const [L, a, b] = oklab(toLinear(c[0] / 255), toLinear(c[1] / 255), toLinear(c[2] / 255));
|
|
143
|
+
const C = Math.hypot(a, b);
|
|
144
|
+
if (C < 1e-4) return color;
|
|
145
|
+
const ua = a / C, ub = b / C;
|
|
146
|
+
const want = C * (1 + .5 * t);
|
|
147
|
+
let best = null, bestC = C;
|
|
148
|
+
/* the lightness from the colour's own down to 15% deeper, in steps; at
|
|
149
|
+
each, the most chroma the screen shows up to `want` */
|
|
150
|
+
for (let k = 0; k <= 6; k++) {
|
|
151
|
+
const Lk = L * (1 - .15 * t * k / 6);
|
|
152
|
+
let lo = 0, hi = want;
|
|
153
|
+
for (let it = 0; it < 18; it++) {
|
|
154
|
+
const mid = (lo + hi) / 2;
|
|
155
|
+
if (inGamut(fromOklab(Lk, ua * mid, ub * mid))) lo = mid;
|
|
156
|
+
else hi = mid;
|
|
157
|
+
}
|
|
158
|
+
/* deeper only for what it gains: each step must buy real chroma */
|
|
159
|
+
if (lo > bestC + .004 * k) {
|
|
160
|
+
bestC = lo;
|
|
161
|
+
best = fromOklab(Lk, ua * lo, ub * lo);
|
|
162
|
+
}
|
|
163
|
+
if (lo >= want - 1e-4) break;
|
|
164
|
+
}
|
|
165
|
+
if (!best) return color;
|
|
166
|
+
const out = best.map((v) => Math.round(255 * toSrgb(Math.min(1, Math.max(0, v)))));
|
|
167
|
+
return `rgb(${out[0]} ${out[1]} ${out[2]})`;
|
|
149
168
|
}
|